# vim:set ft= ts=4 sw=4 et fdm=marker:

use Test::Nginx::Socket::Lua;


plan tests => repeat_each() * (blocks() * 3);


our $http_config = <<'_EOC_';
    lua_package_path "${prefix}../../script/?.ljbc;${prefix}../../script/?.lua;;";
_EOC_

no_shuffle();
# no_long_string();

run_tests();

__DATA__


=== TEST 1-1: decode valid numbers
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local cases = {
                    "0",
                    "-0",
                    "1",
                    "-1",
                    "0.1",
                    "-0.1",
                    "1234",
                    "-1234",
                    "12.34",
                    "-12.34",
                    "12E0",
                    "12E1",
                    "12e34",
                    "12E-0",
                    "12e+1",
                    "12e-34",
                    "-12E0",
                    "-12E1",
                    "-12e34",
                    "-12E-0",
                    "-12e+1",
                    "-12e-34",
                    "1.2E0",
                    "1.2E1",
                    "1.2e34",
                    "1.2E-0",
                    "1.2e+1",
                    "1.2e-34",
                    "-1.2E0",
                    "-1.2E1",
                    "-1.2e34",
                    "-1.2E-0",
                    "-1.2e+1",
                    "-1.2e-34",
                    "0E0",
                    "0E1",
                    "0e34",
                    "0E-0",
                    "0e+1",
                    "0e-34",
                    "-0E0",
                    "-0E1",
                    "-0e34",
                    "-0E-0",
                    "-0e+1",
                    "-0e-34",
                }

                for i = 1, #cases do
                    local RES
                    do
                        local input  = cases[i]

                        local opt = {
                            use_json_number = false,
                        }

                        local res, err = json.decode(input, opt)
                        assert(err == nil, string.format("err should be nil, but got '%s'", err))

                        -- export
                        RES = res
                    end

                    local EXPECT = tonumber(cases[i])

                    if EXPECT ~= RES then
                        assert(false, string.format("[%s] expect: %s, actural: %s", k, EXPECT, RES))
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 1-2: decode valid numbers with 'use_json_number' option
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local cases = {
                    "0",
                    "-0",
                    "1",
                    "-1",
                    "0.1",
                    "-0.1",
                    "1234",
                    "-1234",
                    "12.34",
                    "-12.34",
                    "12E0",
                    "12E1",
                    "12e34",
                    "12E-0",
                    "12e+1",
                    "12e-34",
                    "-12E0",
                    "-12E1",
                    "-12e34",
                    "-12E-0",
                    "-12e+1",
                    "-12e-34",
                    "1.2E0",
                    "1.2E1",
                    "1.2e34",
                    "1.2E-0",
                    "1.2e+1",
                    "1.2e-34",
                    "-1.2E0",
                    "-1.2E1",
                    "-1.2e34",
                    "-1.2E-0",
                    "-1.2e+1",
                    "-1.2e-34",
                    "0E0",
                    "0E1",
                    "0e34",
                    "0E-0",
                    "0e+1",
                    "0e-34",
                    "-0E0",
                    "-0E1",
                    "-0e34",
                    "-0E-0",
                    "-0e+1",
                    "-0e-34",
                }

                for i = 1, #cases do
                    local RES
                    do
                        local input  = cases[i]

                        local opt = {
                            use_json_number = true,
                        }

                        local res, err = json.decode(input, opt)
                        assert(err == nil, string.format("err should be nil, but got '%s'", err))

                        -- export
                        RES = res
                    end

                    local EXPECT = cases[i]

                    if EXPECT ~= RES:string() then
                        assert(false, string.format("[%s] expect: %s, actural: %s", k, EXPECT, RES:string()))
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 1-3: decode invalid numbers
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local cases = {
                    "",
                    "  ",
                    "invalid",
                    "1.0.1",
                    "1..1",
                    "-1-2",
                    "012a42",
                    "01.2",
                    "012",
                    "12E12.12",
                    "1e2e3",
                    "1e+-2",
                    "1e--23",
                    "1e",
                    "e1",
                    "1e+",
                    "1ea",
                    "1a",
                    "1.a",
                    "1.",
                    "01",
                    "1.e1",
                }

                for i = 1, #cases do
                    local input  = cases[i]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)

                    -- local cjson = require("cjson")
                    -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                    assert(res == nil
                          ,string.format("test '%s': 'res' should be nil, but got '%s'", input, res))
                    assert(err ~= nil
                          ,"'err' should not be nil")
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 1-4: decode valid numbers with 'use_json_number' option
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local cases = {
                    "9007199254740992",
                    "18446744073709551616",
                    "9007199254740991.00001",
                    "-9007199254740992",
                    "-18446744073709551616",
                    "-9007199254740991.00001",
                }

                for i = 1, #cases do
                    local RES
                    do
                        local input  = cases[i]

                        local opt = {
                            use_json_number = true,
                        }

                        local res, err = json.decode(input, opt)
                        assert(err == nil, string.format("err should be nil, but got '%s'", err))

                        -- export
                        RES = res
                    end

                    local EXPECT = cases[i]

                    if EXPECT ~= RES:string() then
                        assert(false, string.format("[%s] expect: %s, actural: %s", k, EXPECT, RES:string()))
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 2-1: decode simple json
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local cases = {
                    'null',
                    'true',
                    'false',
                    '0',
                    '0.1',
                    '"a"',
                    '{}',
                    '[]',
                }

                local expected = {
                    [1] = nil,
                    [2] = true,
                    [3] = false,
                    [4] = 0,
                    [5] = 0.1,
                    [6] = "a",
                    [7] = {},
                    [8] = {},
                }

                for i = 1, #cases do
                    local input  = cases[i]

                    local RES
                    do

                        local opt = {
                            use_json_number = false,
                        }

                        local res, err = json.decode(input, opt)
                        assert(err == nil, string.format("test '%s': err should be nil, but got '%s'", input, err))

                        -- export
                        RES = res
                    end

                    local EXPECT = expected[i]

                    if type(EXPECT) == 'table' then
                        if type(RES) ~= 'table' then
                            assert(false, string.format("[%s] expect: %s, actural: %s", input, EXPECT, RES))
                        end
                        if #EXPECT > 0 then
                            for k, v in ipairs(EXPECT) do
                                if v ~= RES[k] then
                                    if  not  json.is_number(v)  then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                                    elseif  not v:equals(RES[k]) then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                                    end
                                end
                            end
                        else
                            for k, v in pairs(EXPECT) do
                                if v ~= RES[k] then
                                    if  not  json.is_number(v)  then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                                    elseif  not v:equals(RES[k]) then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                                    end
                                end
                            end
                        end
                    else
                        if EXPECT ~= RES then
                            assert(false, string.format("[%s] expect: %s, actural: %s", input, EXPECT, RES))
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 2-2: decode simple json with 'use_json_number' option
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local cases = {
                    'null',
                    'true',
                    'false',
                    '0',
                    '0.1',
                    '"a"',
                    '{}',
                    '[]',
                }

                local expected = {
                    [1] = nil,
                    [2] = true,
                    [3] = false,
                    [4] = json.number("0"),
                    [5] = json.number("0.1"),
                    [6] = "a",
                    [7] = {},
                    [8] = {},
                }

                for i = 1, #cases do
                    local input  = cases[i]

                    local RES
                    do

                        local opt = {
                            use_json_number = true,
                        }

                        local res, err = json.decode(input, opt)
                        assert(err == nil, string.format("test '%s': err should be nil, but got '%s'", input, err))

                        -- export
                        RES = res
                    end

                    local EXPECT = expected[i]

                    if type(EXPECT) == 'table' then
                        if type(RES) ~= 'table' then
                            assert(false, string.format("[%s] expect: %s, actural: %s", input, EXPECT, RES))
                        end
                        if #EXPECT > 0 then
                            for k, v in ipairs(EXPECT) do
                                if v ~= RES[k] then
                                    if  not  json.is_number(v)  then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                                    elseif  not v:equals(RES[k]) then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                                    end
                                end
                            end
                        else
                            for k, v in pairs(EXPECT) do
                                if v ~= RES[k] then
                                    if  not  json.is_number(v)  then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                                    elseif  not v:equals(RES[k]) then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                                    end
                                end
                            end
                        end
                    else
                        if EXPECT ~= RES then
                            if  not  json.is_number(EXPECT)  then
                                assert(false, string.format("[%s] expect: %s, actural: %s", input, EXPECT, RES))
                            elseif not EXPECT:equals(RES) then
                                assert(false, string.format("[%s] expect: %s, actural: %s", input, EXPECT:string(), RES:string()))
                            end
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 2-3: decode simple json with white-space padding
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local cases = {
                    '  null',
                    '  true',
                    '  false',
                    '  0',
                    '  0.1',
                    '  "a"',
                    '  {}',
                    '  []',
                    'null   ',
                    'true   ',
                    'false  ',
                    '0      ',
                    '0.1    ',
                    '"a"    ',
                    '{}     ',
                    '[]     ',
                    '  null   ',
                    '  true   ',
                    '  false  ',
                    '  0      ',
                    '  0.1    ',
                    '  "a"    ',
                    '  {}     ',
                    '  []     ',
                }

                local expected = {
                    [1] = nil,
                    [2] = true,
                    [3] = false,
                    [4] = 0,
                    [5] = 0.1,
                    [6] = "a",
                    [7] = {},
                    [8] = {},
                }

                for i = 1, #cases do
                    local input  = cases[i]

                    local RES
                    do

                        local opt = {
                            use_json_number = false,
                        }

                        local res, err = json.decode(input, opt)
                        assert(err == nil, string.format("test '%s': err should be nil, but got '%s'", input, err))

                        -- export
                        RES = res
                    end

                    local EXPECT
                    if (i % #expected) == 0 then
                        EXPECT = expected[#expected]
                    else
                        EXPECT = expected[(i % #expected)]
                    end

                    if type(EXPECT) == 'table' then
                        if type(RES) ~= 'table' then
                            assert(false, string.format("[%s] expect: %s, actural: %s", input, EXPECT, RES))
                        end
                        if #EXPECT > 0 then
                            for k, v in ipairs(EXPECT) do
                                if v ~= RES[k] then
                                    if  not  json.is_number(v)  then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                                    elseif  not v:equals(RES[k]) then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                                    end
                                end
                            end
                        else
                            for k, v in pairs(EXPECT) do
                                if v ~= RES[k] then
                                    if  not  json.is_number(v)  then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                                    elseif  not v:equals(RES[k]) then
                                        assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                                    end
                                end
                            end
                        end
                    else
                        if EXPECT ~= RES then
                            assert(false, string.format("[%s] expect: %s, actural: %s", input, EXPECT, RES))
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 3-1: decode single dimension array
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[[
                        "luffy",
                        19
                    ] ]]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    "luffy",
                    19,
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in ipairs(EXPECT) do
                    if v ~= RES[k] then
                        if  not  json.is_number(v)  then
                            assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                        elseif  not v:equals(RES[k]) then
                            assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 3-2: decode single dimension array with 'use_json_number' option
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[[
                        "luffy",
                        19
                    ] ]]

                    local opt = {
                        use_json_number = true,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    "luffy",
                    json.number(19),
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in ipairs(EXPECT) do
                    if v ~= RES[k] then
                        if  not  json.is_number(v)  then
                            assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                        elseif  not v:equals(RES[k]) then
                            assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 4-1: decode plain object
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[{
                        "name": "luffy",
                        "age" : 19
                    }]]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    name = "luffy",
                    age  = 19,
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in pairs(EXPECT) do
                    if v ~= RES[k] then
                        if  not  json.is_number(v)  then
                            assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                        elseif  not v:equals(RES[k]) then
                            assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 4-2: decode plain object with 'use_json_number' option
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[{
                        "name": "luffy",
                        "age" : 19
                    }]]

                    local opt = {
                        use_json_number = true,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    name = "luffy",
                    age  = json.number("19"),
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in pairs(EXPECT) do
                    if v ~= RES[k] then
                        if  not  json.is_number(v)  then
                            assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                        elseif  not v:equals(RES[k]) then
                            assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 5-1: decode nested array at the last position
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[[
                        "luffy",
                        19,
                        [ "meat", "king" ]
                    ] ]]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    "luffy",
                    19,
                    {
                        "meat",
                        "king",
                    },
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in ipairs(EXPECT) do
                    if type(v) == 'table' then
                        local r = RES[k]
                        for ii, vv in ipairs(v) do
                            if vv ~= r[ii] then
                                if  not  json.is_number(vv)  then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv, r[ii]))
                                elseif  not vv:equals(r[ii]) then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv:string(), (r[ii]):string()))
                                end
                            end
                        end
                    else
                        if v ~= RES[k] then
                            if  not  json.is_number(v)  then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                            elseif  not v:equals(RES[k]) then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                            end
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 5-2: decode nested array at the first position
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[[
                        [ "meat", "king" ],
                        "luffy",
                        19
                    ] ]]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    {
                        "meat",
                        "king",
                    },
                    "luffy",
                    19,
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in ipairs(EXPECT) do
                    if type(v) == 'table' then
                        local r = RES[k]
                        for ii, vv in ipairs(v) do
                            if vv ~= r[ii] then
                                if  not  json.is_number(vv)  then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv, r[ii]))
                                elseif  not vv:equals(r[ii]) then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv:string(), (r[ii]):string()))
                                end
                            end
                        end
                    else
                        if v ~= RES[k] then
                            if  not  json.is_number(v)  then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                            elseif  not v:equals(RES[k]) then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                            end
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 5-3: decode nested array at the first position and the last position
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[[
                        [ "meat", "king" ],
                        "luffy",
                        19,
                        [ "Straw Hat Luffy", "Lucy" ]
                    ] ]]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    {
                        "meat",
                        "king",
                    },
                    "luffy",
                    19,
                    {
                        "Straw Hat Luffy",
                        "Lucy",
                    },
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in ipairs(EXPECT) do
                    if type(v) == 'table' then
                        local r = RES[k]
                        for ii, vv in ipairs(v) do
                            if vv ~= r[ii] then
                                if  not  json.is_number(vv)  then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv, r[ii]))
                                elseif  not vv:equals(r[ii]) then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv:string(), (r[ii]):string()))
                                end
                            end
                        end
                    else
                        if v ~= RES[k] then
                            if  not  json.is_number(v)  then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                            elseif  not v:equals(RES[k]) then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                            end
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 5-4: decode nested array at arbitrary position
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[[
                        [ "meat", "king" ],
                        "luffy",
                        [ "Straw Hat Luffy", "Lucy" ],
                        19
                    ] ]]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    {
                        "meat",
                        "king",
                    },
                    "luffy",
                    {
                        "Straw Hat Luffy",
                        "Lucy",
                    },
                    19,
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in ipairs(EXPECT) do
                    if type(v) == 'table' then
                        local r = RES[k]
                        for ii, vv in ipairs(v) do
                            if vv ~= r[ii] then
                                if  not  json.is_number(vv)  then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv, r[ii]))
                                elseif  not vv:equals(r[ii]) then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv:string(), (r[ii]):string()))
                                end
                            end
                        end
                    else
                        if v ~= RES[k] then
                            if  not  json.is_number(v)  then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                            elseif  not v:equals(RES[k]) then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                            end
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 6-1: decode nested object at the last position
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[{
                        "name" : "luffy",
                        "age"  : 19,
                        "favorite" : { 
                            "1" : "king",
                            "2" : "meat"
                        }
                    }]]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    name = "luffy",
                    age  = 19,
                    favorite = {
                        ["1"] = "king",
                        ["2"] = "meat",
                    },
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in pairs(EXPECT) do
                    if type(v) == 'table' then
                        local r = RES[k]
                        for ii, vv in pairs(v) do
                            if vv ~= r[ii] then
                                if  not  json.is_number(vv)  then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv, r[ii]))
                                elseif  not vv:equals(r[ii]) then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv:string(), (r[ii]):string()))
                                end
                            end
                        end
                    else
                        if v ~= RES[k] then
                            if  not  json.is_number(v)  then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                            elseif  not v:equals(RES[k]) then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                            end
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 6-2: decode nested object at the first position
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[{
                        "favorite" : { 
                            "1" : "king",
                            "2" : "meat"
                        },
                        "name" : "luffy",
                        "age"  : 19
                    }]]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    name = "luffy",
                    age  = 19,
                    favorite = {
                        ["1"] = "king",
                        ["2"] = "meat",
                    },
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in pairs(EXPECT) do
                    if type(v) == 'table' then
                        local r = RES[k]
                        for ii, vv in pairs(v) do
                            if vv ~= r[ii] then
                                if  not  json.is_number(vv)  then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv, r[ii]))
                                elseif  not vv:equals(r[ii]) then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv:string(), (r[ii]):string()))
                                end
                            end
                        end
                    else
                        if v ~= RES[k] then
                            if  not  json.is_number(v)  then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                            elseif  not v:equals(RES[k]) then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                            end
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 6-3: decode nested object at the first position and the last position
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[{
                        "favorite" : { 
                            "1" : "king",
                            "2" : "meat"
                        },
                        "name" : "luffy",
                        "age"  : 19,
                        "alias": {
                            "1" : "Straw Hat Luffy",
                            "2" : "Lucy"
                        }
                    }]]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    name = "luffy",
                    age  = 19,
                    favorite = {
                        ["1"] = "king",
                        ["2"] = "meat",
                    },
                    alias = {
                        ["1"] = "Straw Hat Luffy",
                        ["2"] = "Lucy",
                    },
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in pairs(EXPECT) do
                    if type(v) == 'table' then
                        local r = RES[k]
                        for ii, vv in pairs(v) do
                            if vv ~= r[ii] then
                                if  not  json.is_number(vv)  then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv, r[ii]))
                                elseif  not vv:equals(r[ii]) then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv:string(), (r[ii]):string()))
                                end
                            end
                        end
                    else
                        if v ~= RES[k] then
                            if  not  json.is_number(v)  then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                            elseif  not v:equals(RES[k]) then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                            end
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 6-4: decode nested object at the first position and the last position
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[{
                        "favorite" : { 
                            "1" : "king",
                            "2" : "meat"
                        },
                        "name" : "luffy",
                        "alias": {
                            "1" : "Straw Hat Luffy",
                            "2" : "Lucy"
                        },
                        "age"  : 19
                    }]]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    name = "luffy",
                    age  = 19,
                    favorite = {
                        ["1"] = "king",
                        ["2"] = "meat",
                    },
                    alias = {
                        ["1"] = "Straw Hat Luffy",
                        ["2"] = "Lucy",
                    },
                }

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in pairs(EXPECT) do
                    if type(v) == 'table' then
                        local r = RES[k]
                        for ii, vv in pairs(v) do
                            if vv ~= r[ii] then
                                if  not  json.is_number(vv)  then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv, r[ii]))
                                elseif  not vv:equals(r[ii]) then
                                    assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv:string(), (r[ii]):string()))
                                end
                            end
                        end
                    else
                        if v ~= RES[k] then
                            if  not  json.is_number(v)  then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                            elseif  not v:equals(RES[k]) then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                            end
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 7-1: decode mixed json
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json = require("shared.json")

                local RES
                do
                    local input  = [[{
                        "favoriteFruit" : "banana",
                        "greeting"      : "Hello, Kim! You have 10 unread messages.",
                        "friends" : [
                            { "name": "Higgins Rodriquez", "id": 0 },
                            { "name": "James Floyd"      , "id": 1 },
                            { "name": "Gay Stewart"      , "id": 2 }
                        ],
                        "range" : [0,1,2,3,4,5,6,7,8,9],
                        "tags"  : ["pariatur","ad","eiusmod","sit","et","velit","culpa"],
                        "longitude"  : -57.919246,
                        "latitude"   : -36.022812,
                        "registered" : "Friday, March 21, 2014 9:13 PM",
                        "about"      : "Laborum nulla aliquip ullamco proident excepteur est officia ipsum. Eiusmod exercitation minim ex do labore reprehenderit aliqua minim qui excepteur reprehenderit cupidatat. Sint enim exercitation duis id consequat nisi enim magna. Commodo aliqua id ipsum sit magna enim. Veniam officia in labore fugiat veniam ea laboris ex veniam duis.\r\n",
                        "address"    : "323 Pulaski Street, Ronco, North Carolina, 7701",
                        "phone"      : "+1 (919) 438-2678",
                        "email"      : "kim.griffith@cipromox.biz",
                        "company"    : "CIPROMOX",
                        "name" : {
                            "last"  : "Griffith",
                            "first" : "Kim"
                        },
                        "eyeColor" : "green",
                        "age"      : 26,
                        "picture"  : "http://placehold.it/32x32",
                        "balance"  : "$1,283.55",
                        "isActive" : false,
                        "guid"     : "10ab0392-c5e2-48a3-9473-aa725bad892d",
                        "index"    : 0,
                        "_id"      : "551b91198238a0bcf9a41133"
                    }]]

                    local opt = {
                        use_json_number = false,
                    }

                    local res, err = json.decode(input, opt)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = {
                    favoriteFruit = "banana",
                    greeting      = "Hello, Kim! You have 10 unread messages.",
                    friends = {
                        { name = "Higgins Rodriquez", id = 0 },
                        { name = "James Floyd"      , id = 1 },
                        { name = "Gay Stewart"      , id = 2 }
                    },
                    range = {0,1,2,3,4,5,6,7,8,9},
                    tags  = {"pariatur","ad","eiusmod","sit","et","velit","culpa"},
                    longitude  = -57.919246,
                    latitude   = -36.022812,
                    registered = "Friday, March 21, 2014 9:13 PM",
                    about      = "Laborum nulla aliquip ullamco proident excepteur est officia ipsum. Eiusmod exercitation minim ex do labore reprehenderit aliqua minim qui excepteur reprehenderit cupidatat. Sint enim exercitation duis id consequat nisi enim magna. Commodo aliqua id ipsum sit magna enim. Veniam officia in labore fugiat veniam ea laboris ex veniam duis.\r\n",
                    address    = "323 Pulaski Street, Ronco, North Carolina, 7701",
                    phone      = "+1 (919) 438-2678",
                    email      = "kim.griffith@cipromox.biz",
                    company    = "CIPROMOX",
                    name = {
                        last  = "Griffith",
                        first = "Kim"
                    },
                    eyeColor = "green",
                    age      = 26,
                    picture  = "http://placehold.it/32x32",
                    balance  = "$1,283.55",
                    isActive = false,
                    guid     = "10ab0392-c5e2-48a3-9473-aa725bad892d",
                    index    = 0,
                    _id      = "551b91198238a0bcf9a41133"
                }

                local cjson = require("cjson")
                ngx.log(ngx.NOTICE, cjson.encode(RES))

                for k, v in pairs(EXPECT) do
                    if type(v) == 'table' then
                        local r = RES[k]
                        if #v == 0 then
                            for ii, vv in pairs(v) do
                                if type(vv) == 'table' then
                                    local rr = r[ii]
                                    if #vv == 0 then
                                        for iii, vvv in pairs(vv) do
                                            if vvv ~= rr[iii] then
                                                if  not  json.is_number(vvv)  then
                                                    assert(false, string.format("[%s] expect: %s, actural: %s", iii, vvv, rr[iii]))
                                                elseif  not vvv:equals(rr[iii]) then
                                                    assert(false, string.format("[%s] expect: %s, actural: %s", iii, vvv:string(), (rr[iii]):string()))
                                                end
                                            end
                                        end
                                    else
                                        for iii, vvv in ipairs(vv) do
                                            if vvv ~= rr[iii] then
                                                if  not  json.is_number(vvv)  then
                                                    assert(false, string.format("[%s] expect: %s, actural: %s", iii, vvv, rr[iii]))
                                                elseif  not vvv:equals(rr[iii]) then
                                                    assert(false, string.format("[%s] expect: %s, actural: %s", iii, vvv:string(), (rr[iii]):string()))
                                                end
                                            end
                                        end
                                    end
                                else
                                    if vv ~= r[ii] then
                                        if  not  json.is_number(vv)  then
                                            assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv, r[ii]))
                                        elseif  not vv:equals(r[ii]) then
                                            assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv:string(), (r[ii]):string()))
                                        end
                                    end
                                end
                            end
                        else
                            for ii, vv in ipairs(v) do
                                if type(vv) == 'table' then
                                    local rr = r[ii]
                                    if #vv == 0 then
                                        for iii, vvv in pairs(vv) do
                                            if vvv ~= rr[iii] then
                                                if  not  json.is_number(vvv)  then
                                                    assert(false, string.format("[%s] expect: %s, actural: %s", iii, vvv, rr[iii]))
                                                elseif  not vvv:equals(rr[iii]) then
                                                    assert(false, string.format("[%s] expect: %s, actural: %s", iii, vvv:string(), (rr[iii]):string()))
                                                end
                                            end
                                        end
                                    else
                                        for iii, vvv in ipairs(vv) do
                                            if vvv ~= rr[iii] then
                                                if  not  json.is_number(vvv)  then
                                                    assert(false, string.format("[%s] expect: %s, actural: %s", iii, vvv, rr[iii]))
                                                elseif  not vvv:equals(rr[iii]) then
                                                    assert(false, string.format("[%s] expect: %s, actural: %s", iii, vvv:string(), (rr[iii]):string()))
                                                end
                                            end
                                        end
                                    end
                                else
                                    if vv ~= r[ii] then
                                        if  not  json.is_number(vv)  then
                                            assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv, r[ii]))
                                        elseif  not vv:equals(r[ii]) then
                                            assert(false, string.format("[%s] expect: %s, actural: %s", ii, vv:string(), (r[ii]):string()))
                                        end
                                    end
                                end
                            end
                        end
                    else
                        if v ~= RES[k] then
                            if  not  json.is_number(v)  then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v, RES[k]))
                            elseif  not v:equals(RES[k]) then
                                assert(false, string.format("[%s] expect: %s, actural: %s", k, v:string(), (RES[k]):string()))
                            end
                        end
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 8-1: encode plain object
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local cases = {
                    [1] = nil,
                    [2] = true,
                    [3] = false,
                    [4] = 0,
                    [5] = 0.1,
                    [6] = json.number("-0.2"),
                    [7] = "a",
                    [8] = {},
                }

                local expected = {
                    'null',
                    'true',
                    'false',
                    '0',
                    '0.1',
                    '-0.2',
                    '"a"',
                    '{}',
                }

                for i = 1, #cases do
                    local input = cases[i]

                    local RES
                    do
                        local res, err = json.encode(input)
                        assert(err == nil, string.format("err should be nil, but got '%s'", err))

                        -- export
                        RES = res
                    end

                    local EXPECT = expected[i]

                    -- local cjson = require("cjson")
                    -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                    if EXPECT ~= RES then
                        assert(false, string.format("test [%d]: expect: %s, actural: %s", i, EXPECT, RES))
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 8-2: encode empty table
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local cases = {
                    {
                        input  = {},
                        mapper = mapper.array(),
                        result = '[]'
                    },
                    {
                        input  = {},
                        result = '{}'
                    },
                }

                for i = 1, #cases do
                    local case = cases[i]
                    local input  = case.input
                    local mapper = case.mapper 
                    local expect = case.result 

                    local RES
                    do
                        local res, err = json.encode(input, mapper)
                        assert(err == nil, string.format("err should be nil, but got '%s'", err))

                        -- export
                        RES = res
                    end

                    local EXPECT = expect

                    -- local cjson = require("cjson")
                    -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                    if EXPECT ~= RES then
                        assert(false, string.format("test [%d]: expect: %s, actural: %s", i, EXPECT, RES))
                    end
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 8-3: encode plain object with mapper (1)
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        name = "luffy",
                        age  = 19,
                    }

                    local mapper = {
                        mapper.scalar("age"),
                        mapper.scalar("name"),
                    }

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = [[{"age":19,"name":"luffy"}]]

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                if EXPECT ~= RES then
                    assert(false, string.format("expect: %s, actural: %s", EXPECT, RES))
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 8-4: encode plain object with mapper (2)
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        name = "luffy",
                        age  = 19,
                    }

                    local mapper = {
                        mapper.scalar("name"),
                        mapper.scalar("age"),
                    }

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = [[{"name":"luffy","age":19}]]

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                if EXPECT ~= RES then
                    assert(false, string.format("expect: %s, actural: %s", EXPECT, RES))
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 8-5: encode plain object without mapper
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        name = "luffy",
                        age  = 19,
                    }

                    local mapper = nil

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local PATTERN = [[^\{("name":"luffy"|"age":19),("name":"luffy"|"age":19)\}$]]
                local matched = ngx.re.match(RES, PATTERN)

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(matched))

                assert(matched, string.format("expect: /%s/, actural: %s", PATTERN, RES))
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 8-6: encode single dimension array without mapper
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        "luffy",
                        "zoro",
                        "nami",
                        "usopp",
                        "sanji",
                        "chopper",
                        "robin",
                        "franky",
                        "brook",
                    }

                    local mapper = nil

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = '["luffy","zoro","nami","usopp","sanji","chopper","robin","franky","brook"]'

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                if EXPECT ~= RES then
                    assert(false, string.format("expect: %s, actural: %s", EXPECT, RES))
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 8-7: encode single dimension array with mapper
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        "luffy",
                        "zoro",
                        "nami",
                        "usopp",
                        "sanji",
                        "chopper",
                        "robin",
                        "franky",
                        "brook",
                    }

                    local mapper = mapper.array(nil, mapper.scalar())

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = '["luffy","zoro","nami","usopp","sanji","chopper","robin","franky","brook"]'

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                if EXPECT ~= RES then
                    assert(false, string.format("expect: %s, actural: %s", EXPECT, RES))
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 8-8: encode objects within a single dimension array with mapper (1)
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        { name = "luffy"  , age = 19 },
                        { name = "zoro"   , age = 21 },
                        { name = "nami"   , age = 20 },
                        { name = "usopp"  , age = 19 },
                        { name = "sanji"  , age = 21 },
                        { name = "chopper", age = 17 },
                        { name = "robin"  , age = 30 },
                        { name = "franky" , age = 36 },
                        { name = "brook"  , age = 90 },
                    }

                    local mapper = mapper.array(
                        nil, mapper.object(
                            nil, {
                                mapper.scalar("name"),
                                mapper.scalar("age"),
                            }
                        ))

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = '['
                    ..'{"name":"luffy","age":19},'
                    ..'{"name":"zoro","age":21},'
                    ..'{"name":"nami","age":20},'
                    ..'{"name":"usopp","age":19},'
                    ..'{"name":"sanji","age":21},'
                    ..'{"name":"chopper","age":17},'
                    ..'{"name":"robin","age":30},'
                    ..'{"name":"franky","age":36},'
                    ..'{"name":"brook","age":90}'
                    ..']'

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                if EXPECT ~= RES then
                    assert(false, string.format("expect: %s, actural: %s", EXPECT, RES))
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 8-9: encode objects within a single dimension array with mapper (2)
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        { name = "luffy"  , age = 19 },
                        { name = "zoro"   , age = 21 },
                        { name = "nami"   , age = 20 },
                        { name = "usopp"  , age = 19 },
                        { name = "sanji"  , age = 21 },
                        { name = "chopper", age = 17 },
                        { name = "robin"  , age = 30 },
                        { name = "franky" , age = 36 },
                        { name = "brook"  , age = 90 },
                    }

                    local mapper = mapper.array(
                        nil, mapper.object(
                            nil, {
                                mapper.scalar("age"),
                                mapper.scalar("name"),
                            }
                        ))

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = '['
                    ..'{"age":19,"name":"luffy"},'
                    ..'{"age":21,"name":"zoro"},'
                    ..'{"age":20,"name":"nami"},'
                    ..'{"age":19,"name":"usopp"},'
                    ..'{"age":21,"name":"sanji"},'
                    ..'{"age":17,"name":"chopper"},'
                    ..'{"age":30,"name":"robin"},'
                    ..'{"age":36,"name":"franky"},'
                    ..'{"age":90,"name":"brook"}'
                    ..']'

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                if EXPECT ~= RES then
                    assert(false, string.format("expect: %s, actural: %s", EXPECT, RES))
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 8-10: encode single dimension array within a plain object with mapper
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        name = "luffy",
                        age  = 19,
                        favorite = {
                            "king",
                            "meat",
                        },
                    }

                    local mapper = {
                        mapper.scalar("name"),
                        mapper.scalar("age"),
                        mapper.array("favorite"),
                    }

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = '{"name":"luffy","age":19,"favorite":["king","meat"]}'


                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                if EXPECT ~= RES then
                    assert(false, string.format("expect: %s, actural: %s", EXPECT, RES))
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 9-1: encode mixed object without mapper
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        favoriteFruit = "banana",
                        greeting      = "Hello, Kim! You have 10 unread messages.",
                        friends = {
                            { name = "Higgins Rodriquez", id = 0 },
                            { name = "James Floyd"      , id = 1 },
                            { name = "Gay Stewart"      , id = 2 }
                        },
                        range = {0,1,2,3,4,5,6,7,8,9},
                        tags  = {"pariatur","ad","eiusmod","sit","et","velit","culpa"},
                        longitude  = -57.919246,
                        latitude   = -36.022812,
                        registered = "Friday, March 21, 2014 9:13 PM",
                        about      = "Laborum nulla aliquip ullamco proident excepteur est officia ipsum. Eiusmod exercitation minim ex do labore reprehenderit aliqua minim qui excepteur reprehenderit cupidatat. Sint enim exercitation duis id consequat nisi enim magna. Commodo aliqua id ipsum sit magna enim. Veniam officia in labore fugiat veniam ea laboris ex veniam duis.\r\n",
                        address    = "323 Pulaski Street, Ronco, North Carolina, 7701",
                        phone      = "+1 (919) 438-2678",
                        email      = "kim.griffith@cipromox.biz",
                        company    = "CIPROMOX",
                        name = {
                            last  = "Griffith",
                            first = "Kim"
                        },
                        eyeColor = "green",
                        age      = 26,
                        picture  = "http://placehold.it/32x32",
                        balance  = "$1,283.55",
                        isActive = false,
                        guid     = "10ab0392-c5e2-48a3-9473-aa725bad892d",
                        index    = 0,
                        _id      = "551b91198238a0bcf9a41133"
                    }

                    local mapper = nil

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local PATTERN = [[^\{.{1101}\}$]]
                local matched = ngx.re.match(RES, PATTERN)

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(matched))

                assert(matched, string.format("expect: /%s/, actural: %s", PATTERN, RES))
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 9-2: encode mixed object with mapper
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        favoriteFruit = "banana",
                        greeting      = "Hello, Kim! You have 10 unread messages.",
                        friends = {
                            { name = "Higgins Rodriquez", id = 0 },
                            { name = "James Floyd"      , id = 1 },
                            { name = "Gay Stewart"      , id = 2 }
                        },
                        range = {0,1,2,3,4,5,6,7,8,9},
                        tags  = {"pariatur","ad","eiusmod","sit","et","velit","culpa"},
                        longitude  = -57.919246,
                        latitude   = -36.022812,
                        registered = "Friday, March 21, 2014 9:13 PM",
                        about      = "Laborum nulla aliquip ullamco proident excepteur est officia ipsum. Eiusmod exercitation minim ex do labore reprehenderit aliqua minim qui excepteur reprehenderit cupidatat. Sint enim exercitation duis id consequat nisi enim magna. Commodo aliqua id ipsum sit magna enim. Veniam officia in labore fugiat veniam ea laboris ex veniam duis.\r\n",
                        address    = "323 Pulaski Street, Ronco, North Carolina, 7701",
                        phone      = "+1 (919) 438-2678",
                        email      = "kim.griffith@cipromox.biz",
                        company    = "CIPROMOX",
                        name = {
                            last  = "Griffith",
                            first = "Kim"
                        },
                        eyeColor = "green",
                        age      = 26,
                        picture  = "http://placehold.it/32x32",
                        balance  = "$1,283.55",
                        isActive = false,
                        guid     = "10ab0392-c5e2-48a3-9473-aa725bad892d",
                        index    = 0,
                        _id      = "551b91198238a0bcf9a41133"
                    }

                    local mapper = {
                        mapper.scalar("index"),
                        mapper.scalar("_id"),
                        mapper.scalar("guid"),
                        mapper.object("name",{
                            mapper.scalar("first"),
                            mapper.scalar("last"),
                        }),
                        mapper.scalar("phone"),
                        mapper.scalar("email"),
                        mapper.scalar("age"),
                        mapper.scalar("address"),
                        mapper.scalar("picture"),
                        mapper.scalar("company"),
                        mapper.scalar("eyeColor"),
                        mapper.scalar("about"),
                        mapper.scalar("favoriteFruit"),
                        mapper.scalar("balance"),
                        mapper.array("friends",
                            mapper.object(nil, {
                                mapper.scalar("id"),
                                mapper.scalar("name"),
                            })
                        ),
                        mapper.scalar("registered"),
                        mapper.scalar("longitude"),
                        mapper.scalar("latitude"),
                        mapper.scalar("isActive"),
                        mapper.scalar("greeting"),
                        mapper.array("range"),
                        mapper.array("tags"),
                    }

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = '{'
                    ..[["index":0,]]
                    ..[["_id":"551b91198238a0bcf9a41133",]]
                    ..[["guid":"10ab0392-c5e2-48a3-9473-aa725bad892d",]]
                    ..[["name":{"first":"Kim","last":"Griffith"},]]
                    ..[["phone":"+1 (919) 438-2678",]]
                    ..[["email":"kim.griffith@cipromox.biz",]]
                    ..[["age":26,]]
                    ..[["address":"323 Pulaski Street, Ronco, North Carolina, 7701",]]
                    ..[["picture":"http://placehold.it/32x32",]]
                    ..[["company":"CIPROMOX",]]
                    ..[["eyeColor":"green",]]
                    ..[["about":"Laborum nulla aliquip ullamco proident excepteur est officia ipsum. Eiusmod exercitation minim ex do labore reprehenderit aliqua minim qui excepteur reprehenderit cupidatat. Sint enim exercitation duis id consequat nisi enim magna. Commodo aliqua id ipsum sit magna enim. Veniam officia in labore fugiat veniam ea laboris ex veniam duis.\r\n",]]
                    ..[["favoriteFruit":"banana",]]
                    ..[["balance":"$1,283.55",]]
                    ..[["friends":[{"id":0,"name":"Higgins Rodriquez"},{"id":1,"name":"James Floyd"},{"id":2,"name":"Gay Stewart"}],]]
                    ..[["registered":"Friday, March 21, 2014 9:13 PM",]]
                    ..[["longitude":-57.919246,]]
                    ..[["latitude":-36.022812,]]
                    ..[["isActive":false,]]
                    ..[["greeting":"Hello, Kim! You have 10 unread messages.",]]
                    ..[["range":[0,1,2,3,4,5,6,7,8,9],]]
                    ..[["tags":["pariatur","ad","eiusmod","sit","et","velit","culpa"]}]]

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                if EXPECT ~= RES then
                    assert(false, string.format("expect: %s, actural: %s", EXPECT, RES))
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 9-3: encode mixed object with mapper only partial field
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        favoriteFruit = "banana",
                        greeting      = "Hello, Kim! You have 10 unread messages.",
                        friends = {
                            { name = "Higgins Rodriquez", id = 0 },
                            { name = "James Floyd"      , id = 1 },
                            { name = "Gay Stewart"      , id = 2 }
                        },
                        range = {0,1,2,3,4,5,6,7,8,9},
                        tags  = {"pariatur","ad","eiusmod","sit","et","velit","culpa"},
                        longitude  = -57.919246,
                        latitude   = -36.022812,
                        registered = "Friday, March 21, 2014 9:13 PM",
                        about      = "Laborum nulla aliquip ullamco proident excepteur est officia ipsum. Eiusmod exercitation minim ex do labore reprehenderit aliqua minim qui excepteur reprehenderit cupidatat. Sint enim exercitation duis id consequat nisi enim magna. Commodo aliqua id ipsum sit magna enim. Veniam officia in labore fugiat veniam ea laboris ex veniam duis.\r\n",
                        address    = "323 Pulaski Street, Ronco, North Carolina, 7701",
                        phone      = "+1 (919) 438-2678",
                        email      = "kim.griffith@cipromox.biz",
                        company    = "CIPROMOX",
                        name = {
                            last  = "Griffith",
                            first = "Kim"
                        },
                        eyeColor = "green",
                        age      = 26,
                        picture  = "http://placehold.it/32x32",
                        balance  = "$1,283.55",
                        isActive = false,
                        guid     = "10ab0392-c5e2-48a3-9473-aa725bad892d",
                        index    = 0,
                        _id      = "551b91198238a0bcf9a41133"
                    }

                    local mapper = {
                        mapper.scalar("_id"),
                        mapper.scalar("guid"),
                        mapper.object("name",{
                            mapper.scalar("first"),
                            mapper.scalar("last"),
                        }),
                        mapper.scalar("email"),
                        mapper.scalar("picture"),
                        mapper.scalar("about"),
                        mapper.scalar("favoriteFruit"),
                        mapper.array("friends",
                            mapper.object(nil, {
                                mapper.scalar("name"),
                            })
                        ),
                        mapper.array("tags"),
                    }

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = '{'
                    ..[["_id":"551b91198238a0bcf9a41133",]]
                    ..[["guid":"10ab0392-c5e2-48a3-9473-aa725bad892d",]]
                    ..[["name":{"first":"Kim","last":"Griffith"},]]
                    ..[["email":"kim.griffith@cipromox.biz",]]
                    ..[["picture":"http://placehold.it/32x32",]]
                    ..[["about":"Laborum nulla aliquip ullamco proident excepteur est officia ipsum. Eiusmod exercitation minim ex do labore reprehenderit aliqua minim qui excepteur reprehenderit cupidatat. Sint enim exercitation duis id consequat nisi enim magna. Commodo aliqua id ipsum sit magna enim. Veniam officia in labore fugiat veniam ea laboris ex veniam duis.\r\n",]]
                    ..[["favoriteFruit":"banana",]]
                    ..[["friends":[{"name":"Higgins Rodriquez"},{"name":"James Floyd"},{"name":"Gay Stewart"}],]]
                    ..[["tags":["pariatur","ad","eiusmod","sit","et","velit","culpa"]}]]

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                if EXPECT ~= RES then
                    assert(false, string.format("expect: %s, actural: %s", EXPECT, RES))
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]



=== TEST 10-1: encode json number
--- http_config eval: $::http_config
--- config
        location = /t {
            content_by_lua_block {
                local json   = require("shared.json")
                local mapper = json.Mapper

                local RES
                do
                    local input  = {
                        name = "luffy",
                        age  = json.number(19),
                    }

                    local mapper = {
                        mapper.scalar("age"),
                        mapper.scalar("name"),
                    }

                    local res, err = json.encode(input, mapper)
                    assert(err == nil, string.format("err should be nil, but got '%s'", err))

                    -- export
                    RES = res
                end

                local EXPECT = [[{"age":19,"name":"luffy"}]]

                -- local cjson = require("cjson")
                -- ngx.log(ngx.NOTICE, cjson.encode(RES))

                if EXPECT ~= RES then
                    assert(false, string.format("expect: %s, actural: %s", EXPECT, RES))
                end
            }
        }
--- request
GET /t
--- response_body
--- error_code: 200
--- no_error_log
[error]


